# -*- coding: utf-8 -*-
# @Time    : 2024/4/20 21:37
# @Author  : Alvin
# @File    : LogisticsInfoHandler.py
# @Des     : 获取物流单号处理类
import json
import logging
import traceback

import requests
from toollib.guid import SnowFlake

from constants import Constants
from model.GetNumParam import GetNumParam
from server.handler.LogisticsBaseHandler import LogisticsBaseHandler
from utils import CheUtil, BussinessUtil


class LogisticsInfoHandler(LogisticsBaseHandler):

    def __init__(self):
        super(LogisticsInfoHandler, self).__init__()
        self.reRequestIndex = 0

    def handle_create_logistics_num(self, rec_data):
        """
        处理创建物流订单事件
        :param rec_data:
        :return:
        """
        try:
            senderPhone = rec_data.get("senderPhone")
            senderName = rec_data.get("senderName")
            sendAddressDetail = rec_data.get("sendAddressDetail")
            kdMobile = rec_data.get("kdMobile")
            orderId = rec_data.get("orderId")
            goodsCount = rec_data.get("goodsCount")
            goodsTitle = rec_data.get("goodsTitle")
            if not orderId:
                rec_data['orderId'] = BussinessUtil.generate_random_digits()
            if not goodsCount:
                rec_data['goodsCount'] = 1
            if not goodsTitle:
                rec_data['goodsTitle'] = "服装"
            if not senderPhone:
                rec_data['senderPhone'] = Constants.senderPhone
            if not senderName:
                rec_data['senderName'] = Constants.senderName
            if not sendAddressDetail:
                rec_data['sendAddressDetail'] = Constants.sendAddressDetail
            if not kdMobile:
                rec_data['kdMobile'] = ''
            param = GetNumParam(**rec_data)
        except Exception as ex:
            raise Exception(f"参数有误，请检查参数是否有误，{str(ex)}")
        # 校验参数是否合法
        self.verify_param_is_legal(param)

        # 校验用户信息
        if param.kdMobile:
            cost = Constants.BaseContent.sync_order_cost_1
        else:
            cost = Constants.BaseContent.sync_order_cost_2
        user_info = self.check_user_info_is_legal(param.userId, cost)
        if not user_info:
            return None
        # 检查系统登录状态
        isLogined = self.check_user_is_logined()
        if not isLogined:
            logging.info("系统登录失败，无法进行买单业务")
            raise Exception("服务器内部异常，请联系管理员解决")
        # 处理创建物流单号事件
        mailNo_gift, mailNo_self = self.real_handle_create_logistics_num_action(param)
        if mailNo_self is not None:
            # 插入数据库：
            self.handle_save_info_2_db(param, user_info, mailNo_gift, mailNo_self, cost)

            result = {
                "expressName": Constants.logistics_name,
                "expressCode": mailNo_gift,
                "userId": param.userId,
                "orderCost": cost
            }
            return result
        else:
            return None

    def verify_param_is_legal(self, param: GetNumParam):
        """
        校验参数是否合法,此处无需返回值，有问题直接抛异常
        1、同步单：省市区必传
                 上家单号必传
        :param param:
        :return:
        """
        if not param.receiveProvince or not param.receiverCity:
            raise Exception("请传入省市区及详细地址")
        if "集运仓" in param.receiverAddressDetail or "集货仓" in param.receiverAddressDetail:
            raise Exception("暂不支持集运仓订单同步")

        if not param.userId:
            raise Exception("用户参数为空")
        mailNo = param.mailNo
        if not mailNo or mailNo == "null" or not param.receiverName or not param.receiverPhone or not param.receiveProvince or not param.receiverCity:
            raise Exception("参数有误，请检查必传参数是否为空")
        if param.kdMobile:
            is_true = BussinessUtil.is_valid_phone(param.kdMobile)
            if not is_true:
                raise Exception("传入的快递联系电话格式不正确")
            if not param.senderPhone:
                param.senderPhone = param.kdMobile
        is_have_chinese = BussinessUtil.jude_str_is_have_chinese(param.mailNo)
        if is_have_chinese:
            raise Exception("快递单号不能包含中文")
        return True

    def handle_save_info_2_db(self, param: GetNumParam, user_info, mailNo_gift, mailNo_self, cost):
        """
        处理保存数据入库事件
        所有数据入库的入口
        :param param: 原始参数
        :param mailNo_gift:新单号
        :param user_info: 用户信息
        :param mailNo_self: 存在库里面的账号，不含前缀78210
        :param cost: 扣费
        :return:
        """

        order_base_id = SnowFlake().gen_uid()
        user_id = user_info['id']
        self.db_handler.update_user_balance_by_id(user_id, cost)

        # 主表新增数据
        base_order_info = BussinessUtil.get_base_order_dict(order_base_id, param, cost, user_id)
        is_save_success = self.db_handler.insert_base_order_info(base_order_info)
        if not is_save_success:
            logging.info(f"主表数据保存失败，保存参数：{base_order_info}")
            raise Exception("无法保存数据，请联系管理员")

        sync_order_info = BussinessUtil.get_sync_order_dict(order_base_id, param, mailNo_gift, mailNo_self)
        self.db_handler.insert_sync_order_info(sync_order_info)

        return cost

    def check_user_info_is_legal(self, userId, orderCost):
        """
        1、检查用户是否存在
        2、检查积分够不够
        :param userId:
        :param orderCost:订单所需积分
        :return:
        """
        user_info = self.db_handler.get_user_by_id(userId)
        if not user_info:
            raise Exception("用户不存在")
        cost = user_info.get("balance", 0)
        if cost <= orderCost:
            raise Exception("用户余额不足，无法创建订单")
        return user_info

    def real_handle_create_logistics_num_action(self, param: GetNumParam):
        """
        处理创建物流单号事件
        :param param:
        :return:
        """
        raw_mail_no = CheUtil.get_num_from_mail_no(param.mailNo)
        order_num = param.mailNo[-8:]
        first_num = CheUtil.get_order_first_num(param.express)
        mailNo_self = f"{first_num}{order_num}"

        mailNo_gift = f"{Constants.logistics_code}{mailNo_self}"
        mailNo_self = self.start_create_logistics_num_action(param, mailNo_self)
        if not mailNo_self:
            raise Exception(f"【{mailNo_gift}】创建物流订单失败")
        return mailNo_gift, mailNo_self

    def start_create_logistics_num_action(self, param: GetNumParam, mailNo_self):
        """
        实际创建订单
        :param param:
        :param mailNo_self:新单号
        :return:
        """
        if not param.receiverName:
            param.receiverName = "张先生"
        if not param.receiverPhone:
            param.receiverPhone = Constants.default_tel
        save_billing_token = self.get_save_billing_token()
        receiverInfo = CheUtil.getReceiverInfo(param.receiverName, param.receiverPhone, param.receiverAddressDetail)
        headers = CheUtil.get_request_header(self.token, self.requestToken)
        url = "https://apit9.lqfast.com/lanqiao-tms-app/web/billing/saveBilling"
        goods_list = CheUtil.get_good_list(param.goodsTitle, param.goodsCount)
        order_param = CheUtil.get_create_order_param(self.token, save_billing_token, mailNo_self, goods_list, param, receiverInfo)

        data = json.dumps(order_param, separators=(',', ':'))
        resp_json = requests.post(url, headers=headers, data=data).json()
        logging.info(f"创建运单响应：{resp_json}，参数：{data}")
        create_status = resp_json.get("success")
        if not create_status:
            errmsg = resp_json.get("errmsg")
            if errmsg == '该运单已提交成功':
                raise Exception("请求太快了，请稍候再试...")
            else:
                raise Exception(errmsg)
        data = resp_json.get("data")
        order_no = data.get("unit")
        return order_no

    def get_save_billing_token(self):
        headers = CheUtil.get_request_header(self.token, self.requestToken)
        url = "https://apit9.lqfast.com/lanqiao-tms-app/web/billing/getSaveBillingToken"
        data = {
            "m": "func",
            "n": "getSaveBillingToken",
            "p": {
                "type": 7
            },
            "l": "",
            "v": "",
            "u": CheUtil.get_param_u(self.token),
            "r": "k",
            "s": "k",
            "t": BussinessUtil.get_current_timetamp()
        }
        data = json.dumps(data, separators=(',', ':'))
        resp_json = requests.post(url, headers=headers, data=data).json()
        request_status = resp_json.get("success")
        if not request_status:
            logging.error(f"get_save_billing_token 参数：{data},响应：{resp_json}")
            raise Exception("token 校验接口出错，请联系管理员")
        return resp_json.get("data")

    def get_mail_no_gift_detail(self, userId, logisticsNo: str):
        """
        查询物流订单列表
        :param userId:
        :param logisticsNo:
        :return:
        """
        if not userId:
            raise Exception("用户信息不能为空")
        if not logisticsNo:
            raise Exception("传入的单号为空")
        if logisticsNo == '78210':
            raise Exception("传入的单号太少，无法匹配更多数据")
        if not logisticsNo.isdigit():
            raise Exception("传入的单号有误，单号为全数字")
        data_list = self.db_handler.get_mail_no_detail_by_no(userId, logisticsNo)
        return data_list

    def get_custom_user_info(self, userId):
        if not userId:
            raise Exception("用户信息不能为空")
        user_info = self.db_handler.get_custom_user_info(userId)
        return user_info

    def handle_update_logistics_no_picking_code(self, param):
        user_id = param.get("userId", None)
        mailNo_gift = param.get("mailNo_gift", None)
        pickingCode = param.get("pickingCode", None)
        pickingAddress = param.get("pickingAddress", None)
        if not user_id:
            raise Exception("用户信息不能为空")
        if not mailNo_gift or not pickingCode or not pickingAddress:
            raise Exception("物流单号、取件码、取件地址都不能为空")
        user_info = self.db_handler.get_user_by_id(user_id)
        if not user_info:
            raise Exception("未查询到用户信息，更新失败")
        try:
            is_success, msg = self.db_handler.update_logistics_no_picking_code(pickingCode, pickingAddress, mailNo_gift)
            return {
                "result": is_success,
                "msg": msg
            }
        except Exception as ex:
            logging.error(f"取件码更新接口异常,异常内容：{str(ex)}")
            logging.error("traceback.format_exc():\n%s" % traceback.format_exc())
